using System;
using Microsoft.Extensions.Options;
using UniversalAdmin.Application.Configurations;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
using System.Text;
using System.Linq;

namespace UniversalAdmin.Application.Services
{
    public class AppJwtServices : IAppJwtService
    {
        private readonly JwtSettings _jwtSettings;
        public AppJwtServices(IOptions<JwtSettings> jwtOptions)
        {
            _jwtSettings = jwtOptions.Value;
        }

        public string GenerateAccessToken(Guid userId, string username)
        {
            var claims = new[]
            {
                new Claim("UserId", userId.ToString()),
                new Claim(ClaimTypes.Name, username)
            };
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken(
                issuer: _jwtSettings.Issuer,
                audience: _jwtSettings.Audience,
                claims: claims,
                expires: DateTime.UtcNow.AddMinutes(_jwtSettings.ExpireMinutes),
                signingCredentials: creds
            );
            return new JwtSecurityTokenHandler().WriteToken(token);
        }

        public string GenerateRefreshToken()
        {
            var claims = new[]
            {
                new Claim("UserId", Guid.Empty.ToString()),
                new Claim(ClaimTypes.Name, "refresh")
            };
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken(
                issuer: _jwtSettings.Issuer,
                audience: _jwtSettings.Audience,
                claims: claims,
                expires: DateTime.UtcNow.AddMinutes(_jwtSettings.RefreshTokenExpireMinutes),
                signingCredentials: creds
            );
            return new JwtSecurityTokenHandler().WriteToken(token);
        }

        public Guid? ValidateAccessToken(string token)
        {
            var handler = new JwtSecurityTokenHandler();
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey));
            try
            {
                var principal = handler.ValidateToken(token, new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidIssuer = _jwtSettings.Issuer,
                    ValidAudience = _jwtSettings.Audience,
                    ValidateLifetime = true,
                    IssuerSigningKey = key,
                    ClockSkew = TimeSpan.FromSeconds(_jwtSettings.ClockSkewSeconds)
                }, out var validatedToken);
                var userIdClaim = principal.Claims.FirstOrDefault(c => c.Type == "UserId");
                if (userIdClaim != null && Guid.TryParse(userIdClaim.Value, out var userId))
                    return userId;
                return null;
            }
            catch
            {
                return null;
            }
        }

        public (bool isValid, string? token, string? userId, string? userName) ValidateRefreshToken(string refreshToken)
        {
            if (string.IsNullOrWhiteSpace(refreshToken)) return (false, null, null, null);
            var handler = new JwtSecurityTokenHandler();
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey));
            try
            {
                var principal = handler.ValidateToken(refreshToken, new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidIssuer = _jwtSettings.Issuer,
                    ValidAudience = _jwtSettings.Audience,
                    ValidateLifetime = true,
                    IssuerSigningKey = key,
                    ClockSkew = TimeSpan.FromSeconds(_jwtSettings.ClockSkewSeconds)
                }, out var validatedToken);
                var userId = principal.Claims.FirstOrDefault(c => c.Type == "UserId")?.Value;
                var userName = principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;
                return (true, refreshToken, userId, userName);
            }
            catch
            {
                return (false, null, null, null);
            }
        }
    }
} 